#include<cstdio>
#include<cstdlib>
#include<cassert>
#include"shep_json.h"
using namespace std;

class shep_context{
public:
    const char* json;

    shep_context(char* data = nullptr) : json(data) {}

    void expect(char ch){assert(*json == ch); json++;}
};


static void shep_parse_whitespace(shep_context& c){
    const char *p = c.json;
    while(*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r'){
        p++;
    }
    c.json = p;
}

static int shep_parse_null(shep_context& c, shep_value& v){
    c.expect('n');
    if(c.json[0] != 'u' || c.json[1] != 'l' || c.json[2] != 'l'){
        return SHEP_PARSE_INVALID_VALUE;
    }
    c.json += 3;
    v.set_type(SHEP_NULL);
    return SHEP_PARSE_OK;
}

static int shep_parse_true(shep_context& c, shep_value& v){
    c.expect('t');
    if(c.json[0] != 'r' || c.json[1] != 'u' || c.json[2] != 'e'){
        return SHEP_PARSE_INVALID_VALUE;
    }
    c.json += 3;
    v.set_type(SHEP_TRUE);
    return SHEP_PARSE_OK;
}

static int shep_parse_false(shep_context& c, shep_value& v){
    c.expect('f');
    if(c.json[0] != 'a' || c.json[1] != 'l' || c.json[2] != 's' || c.json[3] != 'e'){
        return SHEP_PARSE_INVALID_VALUE;
    }
    c.json += 4;
    v.set_type(SHEP_FALSE);
    return SHEP_PARSE_OK;
}

static int shep_parse_value(shep_context& c, shep_value& v){
    switch(*c.json){
        case 'n':  return shep_parse_null(c, v);
        case 't':  return shep_parse_true(c, v);
        case 'f':  return shep_parse_false(c, v);
        case '\0': return SHEP_PARSE_EXCEPT_VALUE;
        default:   return SHEP_PARSE_INVALID_VALUE; 
    }
}

int shep_parse(shep_value& v, const char* json){
    shep_context c;
    c.json = json;
    v.set_type(SHEP_NULL);
    shep_parse_whitespace(c);
    int temp_val = shep_parse_value(c, v);
    if(temp_val != SHEP_PARSE_OK)return temp_val;
    shep_parse_whitespace(c);
    return (*c.json == '\0' ? SHEP_PARSE_OK : SHEP_PARSE_ROOT_NOT_SINGULAR);
}